package com.chy.mybatis.jdkproxy;

import com.chy.mybatis.cglibproxy.HelloServiceCglib;
import com.chy.mybatis.cglibproxy.TestServiceImpl;

/**
 * 功能：5. JDK动态代理与CGLib代理的区别是什么？
 *
 * 5.1 原理区别：
 *
 * java动态代理是利用反射机制生成一个实现代理接口的匿名类，在调用具体方法前调用InvokeHandler来处理。核心是实现InvocationHandler接口，使用invoke()方法进行面向切面的处理，调用相应的通知。
 *
 * 而cglib动态代理是利用asm开源包，对代理对象类的class文件加载进来，通过修改其字节码生成子类来处理。核心是实现MethodInterceptor接口，使用intercept()方法进行面向切面的处理，调用相应的通知。
 *
 * 1、如果目标对象实现了接口，默认情况下会采用JDK的动态代理实现AOP
 *
 * 2、如果目标对象实现了接口，可以强制使用CGLIB实现AOP
 *
 * 3、如果目标对象没有实现了接口，必须采用CGLIB库，spring会自动在JDK动态代理和CGLIB之间转换
 *
 *
 *
 * 5.2 性能区别：
 *
 * 1、CGLib底层采用ASM字节码生成框架，使用字节码技术生成代理类，在jdk6之前比使用Java反射效率要高。唯一需要注意的是，CGLib不能对声明为final的方法进行代理，因为CGLib原理是动态生成被代理类的子类。
 *
 * 2、在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后，在调用次数较少的情况下，JDK代理效率高于CGLIB代理效率，只有当进行大量调用的时候，jdk6和jdk7比CGLIB代理效率低一点，但是到jdk8的时候，jdk代理效率高于CGLIB代理。
 *
 *
 *
 * 5.3 各自局限：
 *
 * 1、JDK的动态代理机制只能代理实现了接口的类，而不能实现接口的类就不能实现JDK的动态代理。
 *
 * 2、cglib是针对类来实现代理的，他的原理是对指定的目标类生成一个子类，并覆盖其中方法实现增强，但因为采用的是继承，所以不能对final修饰的类进行代理。
 * <p>
 * ──────────────────────────────────────────
 * version  变更日期       修改人    修改说明
 * ------------------------------------------
 * V1.0.0   2022/3/8     CHY     初版
 * ──────────────────────────────────────────
 */
public class HelloServiceMain {

    public static void main(String[] args) {
        //正常代理
        HelloServiceProxy helloHandler = new HelloServiceProxy();
        HelloService proxy = (HelloService) helloHandler.bind(new HelloServiceImpl());
        proxy.sayHello("zhangsan");
        proxy.sayByeBye("zhangsan","lisi");

        HelloServiceCglib helloServiceCglib = new HelloServiceCglib();
        HelloService instance = (HelloService)helloServiceCglib.getInstance(new HelloServiceImpl());
        instance.sayHello("zhangsan");
        instance.sayByeBye("zhangsan","lisi");

        //测试代码 JDK不能代理没有实现接口的类，CGLIB可以代理没有实现接口的类
        TestServiceImpl proxy1 = (TestServiceImpl) helloHandler.bind(new TestServiceImpl());
        proxy1.sayTest("ttt");
        TestServiceImpl instance1 = (TestServiceImpl)helloServiceCglib.getInstance(new TestServiceImpl());
        instance1.sayTest("ttt");
    }
}
